<!--  遍历实现日历，设置插槽，通过插槽向日期添加信息
  问题：一旦切换前一页或后一页，整个日历会重置，所有信息被删除 -->
<template>
  <div class="publicDialog">
    <!-- 直接显示内容 -->
    <div class="contentBody">
      <!-- 顶层添加栏 -->
      <div class="flex-row-center">
        添加：
        <el-date-picker
          style="width: 210px"
          v-model="editForm.time"
          type="date"
          placeholder="选择日期"
          value-format="yyyy-M-d"
        >
        </el-date-picker>
        <el-select
          v-model="editForm.type"
          style="width: 150px; margin-left: 14px"
          placeholder="请选择分类"
        >
          <el-option
            v-for="item in cateOptions"
            :key="item.value"
            :label="item.label"
            :value="item.value"
          >
          </el-option>
        </el-select>
        <el-input
          style="width: 310px; margin-left: 14px"
          v-model="editForm.txt"
          placeholder="请输入内容"
        ></el-input>
        <el-button
          type="primary"
          round
          @click="addConfirm"
          style="margin-left: 12px"
          class="commonBtn width90Height36 borderRadius18 hasBgBtn"
        >
          确定
        </el-button>
        <el-button
          type="primary"
          round
          @click="cancleHandle"
          style="margin-left: 20px"
          class="commonBtn width90Height36 borderRadius18 defalutBorderBtn"
        >
          取消
        </el-button>
      </div>

      <div class="air-calendar-box">
        <table class="sn-calendar-table">
          <!-- 定义表格表头 -->
          <thead>
            <!-- 定义左箭头导航到上个月 -->
            <i class="el-icon-arrow-left iconBtn" @click="preTimeHandle"></i>
            <!-- 定义表头单元格，显示星期几的标签 {{ item }}显示当前星期几-->
            <th
              class="fc-day-header"
              v-for="(item, inx) in weekdays"
              :key="inx"
            >
              {{ item }}
            </th>
            <!-- 定义右箭头导航到下个月 -->
            <i class="el-icon-arrow-right iconBtn" @click="nextTimeHandle"></i>
          </thead>
          <tbody>
            <!--行遍历
            定义一个表格行 <tr>，用于显示一周的数据 
              行遍历 visibleTimetableData 数组中的每一行（每周）。-->
            <tr v-for="(calc, index1) in visibleTimetableData" :key="index1">
              <!--  列遍历
              v-for="(item, idx) in calc" 遍历当前行中的每一天。
                点击当天时调用 clickDay 方法，并传递当天的数据 item。-->
              <td
                v-for="(item, idx) in calc"
                :key="idx"
                :class="{
                  include: item.include,
                  active: activeData && item.date === activeData.date,
                }"
                @click="clickDay(item)"
              >
                <!-- 定义一个插槽，允许父组件插入自定义内容，并传递当前天的数据 item，:row="item" 将当前天的数据传递给插槽。 -->
                <slot name="day" :row="item">
                  <div>
                    <!-- 判断是否显示月份标签 ，当月第一天/第一行第一天 -->
                    <div
                      class="month"
                      v-if="item.day2 == '01' || (index1 == 0 && idx == 0)"
                    >
                      {{ item.month }}月
                    </div>

                    <div class="day">
                      {{ item.day2 }}
                    </div>

                    <div style="margin-top: 30px"></div>
                    <!-- 下拉菜单组件 -->
                    <el-dropdown
                      v-for="(ite, idex) in item.contentList"
                      :key="idex"
                    >
                      <!-- 定义下拉菜单的触发元素。 -->
                      <span class="el-dropdown-link">
                        <div
                          class="contentRow"
                          :class="cateOptions[ite.type].bgColor"
                        >
                          <!-- 根据内容类型 ite.type 获取对应的图标 -->
                          <i :class="cateOptions[ite.type].icon"></i>
                          <p>{{ ite.txt }}</p>
                        </div>
                      </span>
                      <!-- 定义一个下拉菜单项，用于编辑内容。 -->
                      <el-dropdown-menu slot="dropdown">
                        <el-dropdown-item @click.native="editInfoHandle(ite)"
                          ><i class="iconfont icon-bianji"></i
                          >编辑</el-dropdown-item
                        >
                        <el-dropdown-item
                          @click.native="deleteInfoHandle(ite, item)"
                          ><i class="el-icon-delete"></i>删除</el-dropdown-item
                        >
                      </el-dropdown-menu>
                    </el-dropdown>
                  </div>
                </slot>
              </td>
            </tr>
          </tbody>
        </table>
      </div>
      <div class="flex-row-jusCenter">
        <div
          class="flex-row-center"
          v-for="(item, inx) in cateOptions"
          :key="inx"
        >
          <div class="cycle" :class="item.bgColor"></div>
          <span>{{ item.label }}</span>
        </div>
      </div>
    </div>
  </div>
</template>
<script>
export default {
  components: {},
  props: {},
  data () {
    return {
      calendarData: [],
      activeData: null,
      weekdays: ["日", "一", "二", "三", "四", "五", "六"],
      cateOptions: [
        {
          value: 0,
          label: "学习",
          bgColor: "orangeBg",
          icon: "iconfont icon-shexiang",
        },
        {
          value: 1,
          label: "休息",
          bgColor: "blueBg",
          icon: "iconfont icon-record",
        },
        {
          value: 2,
          label: "出去玩",
          bgColor: "greenBg",
          icon: "iconfont icon-yongyan",
        },
        {
          value: 3,
          label: "作业",
          bgColor: "redBg",
          icon: "iconfont icon-fen",
        },
      ],
      editForm: {
        time: "",
        type: null,
        txt: null,
        id: new Date().getTime(),
        editType: "add",
      },
      totalDays: 28,
    };
  },
  computed: {
    visibleTimetableData () {
      let list1 = this.calendarData.slice(0, 7),
        list2 = this.calendarData.slice(7, 14),
        list3 = this.calendarData.slice(14, 21),
        list4 = this.calendarData.slice(21);
      let arr = [];//创建二维数组
      arr.push(list1);
      arr.push(list2);
      arr.push(list3);
      arr.push(list4);
      return arr;
    },
  },
  mounted () {
    this.resetCanlendarDay();//初始化日历数据
  },
  methods: {
    cancleHandle () {
      this.editForm = {
        time: "",
        type: null,
        txt: null,
        id: new Date().getTime(),
        editType: "add",
      };
    },
    /**编辑事件 */
    editInfoHandle (ite) {
      this.editForm = ite;
      this.editForm.editType = "edit";
    },
    /**删除事件 */
    deleteInfoHandle (ite, item) {
      let obj;//存储找到的日期对象
      //从 this.calendarData 中查找与 item.date 匹配的日期对象。
      obj = this.calendarData.find((el) => el.date === item.date);
      //从 obj.contentList 中查找与 ite.id 匹配的事件对象，并获取其索引。
      let subObjIndex = obj.contentList.findIndex((el) => el.id === ite.id);
      //从 obj.contentList 中删除索引为 subObjIndex 的事件对象。
      obj.contentList.splice(subObjIndex, 1);

    },
    /**添加事件 */
    addConfirm () {
      let obj, objIndex;//声明日期变量和索引变量
      obj = this.calendarData.find((el) => el.date === this.editForm.time);
      objIndex = this.calendarData.indexOf(obj);

      if (this.editForm.editType == "add") {
        obj.contentList.push(this.editForm);
      } else {
        let subObjIndex = obj.contentList.findIndex(
          (el) => el.id === this.editForm.id
        );
        obj.contentList.splice(subObjIndex, 1, this.editForm);
      }

      //将更新后的日期对象替换原来的日期对象。
      this.calendarData.splice(objIndex, 1, obj);
      this.$forceUpdate();//强制更新
      // this.editForm = {
      //   time: "",
      //   type: null,
      //   txt: null,
      //   id: new Date().getTime(),
      //   editType: "add",
      // };

    },
    /**导航到上一个月，更新 calendarData 中的数据 */
    preTimeHandle () {
      let preTimeDate = this.calendarData[0];
      this.calendarData = this.getDatesBeforeDate(new Date(preTimeDate.date));
    },
    /**导航到下一个月，更新 calendarData 中的数据。 */
    nextTimeHandle () {
      let lastTimeDate = this.calendarData[this.calendarData.length - 1].date;
      let nextDate = new Date(lastTimeDate);
      nextDate.setDate(nextDate.getDate() + 1);
      this.calendarData = this.getDatesFromDate(nextDate);
    },
    /**从指定的开始日期 startDate 生成未来几天的日期对象 */
    getDatesFromDate (startDate) {
      const dates = [];//初始化日期数组
      //生成从 startDate 开始的未来几天的日期对象。
      for (let i = 0; i < this.totalDays; i++) {
        const date = new Date(startDate.getTime() + i * 24 * 60 * 60 * 1000);
        let curYear = date.getFullYear(),
          curMonth = date.getMonth() + 1,
          curDay = date.getDay(),
          curWeek = date.getDate();
        //创建一个日期对象，该对象表示 startDate 之后 i 天的日期。
        dates.push({
          year: curYear,
          month: curMonth,
          day: curDay,//获取当前日期是星期几（0-6，0表示星期日）。
          day2: curWeek < 10 ? "0" + curWeek : curWeek,//日期，格式化为两位数。
          date: `${curYear}-${curMonth}-${curWeek}`,// 年-月-日
          include: false,
          getTime: date.getTime(),
          contentList: [],
        });
      }
      return dates;//返回生成的日期数组
    },
    /** 从指定的结束日期 endDate 生成前几天的日期对象*/
    getDatesBeforeDate (endDate) {
      const dates = [];
      //生成从 endDate 开始的前几天的日期对象。
      for (let i = this.totalDays; i > 0; i--) {
        const date = new Date(endDate.getTime() - i * 24 * 60 * 60 * 1000);
        let curYear = date.getFullYear(),
          curMonth = date.getMonth() + 1,
          curDay = date.getDay(),
          curWeek = date.getDate();
        dates.push({
          year: curYear,
          month: curMonth,
          day: curDay,
          day2: curWeek < 10 ? "0" + curWeek : curWeek,
          date: `${curYear}-${curMonth}-${curWeek}`,
          include: false,
          getTime: date.getTime(),
          contentList: [],
        });
      }
      //对生成的日期数组进行排序，确保日期按时间顺序排列。
      dates.sort((a, b) => a.getTime - b.getTime);
      return dates;
    },
    /**初始化日历数据 */
    resetCanlendarDay () {
      const today = new Date();
      const twoWeeksAgo = new Date(today.getTime() - 7 * 24 * 60 * 60 * 1000);
      const sunday = new Date(twoWeeksAgo.getTime());
      sunday.setDate(sunday.getDate() - sunday.getDay());
      this.calendarData = this.getDatesFromDate(sunday);//生成日历数据
      /**设置当前激活时间 */
      let curYear = today.getFullYear(),//获取当前年份
        curMonth = today.getMonth() + 1,//获取当前月份从0开始，所以加1
        curDay = today.getDay(),//获取当前星期几
        curWeek = today.getDate();//获取当前日期
      /**创建对象，包含当前时间的所有信息 */
      this.activeData = {
        year: curYear,
        month: curMonth,
        day: curDay,
        day2: curWeek < 10 ? "0" + curWeek : curWeek,
        date: `${curYear}-${curMonth}-${curWeek}`,
        include: false,
        getTime: today.getTime(),
        contentList: [],
      };

    },
    /**点击日历单元格事件 */
    clickDay (row) {
      //使用解构赋值将点击的日期单元格的数据复制到 this.activeData 中，这样可以高亮显示当前选中的日期。
      this.activeData = { ...row };
    },
  },
};
</script>
<style lang="scss" scoped>
.contentBody {
  .contentRow {
    width: 120px;
    height: 30px;
    border-radius: 15px;
    font-size: 12px;
    font-family: PingFang SC;
    font-weight: 500;
    padding: 0 8px;
    margin-left: 10px;
    margin-bottom: 8px;
    box-sizing: border-box;
    color: #ffffff;
    display: flex;
    flex-direction: row;
    align-items: center;
    justify-content: flex-start;
    p {
      max-width: 100px;
      text-overflow: ellipsis;
      overflow: hidden;
      white-space: nowrap;
    }

    i {
      margin-right: 5px;
    }
  }
  .iconBtn {
    cursor: pointer;
    font-size: 20px;
    position: absolute;
    top: 15px;
  }
  .iconBtn:first-child {
    left: 5px;
  }
  .iconBtn:last-child {
    right: 5px;
  }
  .air-calendar-box {
    width: 100%;
    .sn-calendar-table {
      width: 100%;
      border-radius: 4px;
      display: block;
      overflow: hidden;
      thead,
      tbody {
        display: flex;
        flex-wrap: wrap;
        flex-shrink: 0;
        width: 100%;
        border-left: 1px solid #ebeef5;

        box-sizing: border-box;
      }
      tbody {
        border-bottom: 1px solid #ebeef5;
      }
      thead {
        position: relative;
        border-right: 1px solid #ebeef5;
        box-sizing: border-box;
      }
      tr {
        width: 100%;
        border-top: 1px solid #ebeef5;
        box-sizing: border-box;
        min-height: 122px;
        td:nth-child(1),
        td:nth-child(2),
        td:nth-child(3),
        td:nth-child(4),
        td:nth-child(5),
        td:nth-child(6),
        td:nth-child(7) {
          background: #f5f5ff;
        }
      }
      th {
        width: 14.28%;
        min-height: 52px;
        line-height: 52px;
        background: #ffffff;
        text-align: center;
        box-sizing: border-box;
        display: inline-block;
        font-size: 15px;
        font-family: PingFang SC;
        font-weight: 400;
        color: #1966ff;
        border-top: 1px solid #ebeef5;
        box-sizing: border-box;
      }
      td {
        width: 14.28%;
        // min-height: 122px;
        height: 100%;
        display: inline-block;
        position: relative;
        font-size: 14px;
        font-family: Helvetica;
        font-weight: 400;
        color: #686c72;
        box-sizing: border-box;
        cursor: pointer;
        border-right: 1px solid #ebeef5;
        box-sizing: border-box;
        &.include {
          font-size: 14px;
          font-family: Helvetica;
          font-weight: 400;
          color: #686c72;
        }
        &.active {
          border: solid 1px #1966ff;
        }
        .day {
          height: 100%;
          position: absolute;
          right: 20px;
          top: 10px;
        }
        .month {
          position: absolute;
          left: 20px;
          top: 10px;
        }
      }
      tbody {
        .clickDay {
          border: solid 1px #1966ff;
          box-sizing: border-box;
        }
      }
    }
  }
  padding-bottom: 30px;
  /deep/ .el-input__inner {
    height: 36px;
    border-radius: 18px;
  }
  .flex-row-center {
    margin-bottom: 14px;
  }
  .flex-row-jusCenter {
    display: flex;
    flex-direction: row;
    align-items: center;
    justify-content: center;
    margin-top: 18px;
    span {
      margin-left: 8px;
      margin-right: 42px;
    }
  }
  .cycle {
    width: 10px;
    height: 10px;
    border-radius: 50%;
  }
  .redBg {
    background: #f3664f;
  }
  .orangeBg {
    background: #ff892c;
  }
  .blueBg {
    background: #3579ff;
  }
  .greenBg {
    background: #04cba4;
  }
}
</style>
